package models

import (
	"fmt"
	"time"

	"github.com/axgle/mahonia"
)

func GetTime() string {
	return time.Now().Format("15:04:05\t")
}
func (rt *RunTime) 发送线程() {
	defer func() {
		err := recover() //消除panic
		rt.exit <- fmt.Sprintln("发送线程退出", err)
	}()
	for {
		tx := <-rt.txchan
		if _, err := rt.tcp.Write(tx); err != nil {
			panic(err)
		}
	}
}
func (rt *RunTime) 接收线程() {
	fmt.Println(GetTime() + "接收线程启动\r\n")
	defer func() {
		err := recover() //消除panic
		rt.exit <- fmt.Sprintln(GetTime()+"接收线程退出", err)
	}()
	rx := make([]byte, 4096)
	接收指针 := 0
	是否调试 := false
	调试名称 := GetConfig("调试", "角色", "GM")
	for {
		if 是否调试 == false && rt.V角色 != nil {
			if rt.V角色.V名字 == 调试名称 {
				是否调试 = true
			}
		}
		rt.tcp.SetReadDeadline(time.Now().Add(time.Minute))
		rxlen, err := rt.tcp.Read(rx[接收指针:])
		if err != nil {
			panic(err)
		}
		rxlen += 接收指针
		接收指针 = 0
		sc := rx[:rxlen]
		KEY := make([]byte, 256)
		for {
			if len(sc) < 18 {
				break
			}
			解密 := false
			var 编码 uint32

			for i := 0; i < 3; i++ {
				di := (rt.日期KEY + i) % 3
				GetKey(KEY, di)
				//fmt.Printf("第%d次原始数据:%s\r\n", i, Byte2String(sc[:18]))
				编码 = Password(KEY, sc[:18], 0, 0) //先转换前18个
				//fmt.Printf("第%d次编码数据:%s\r\n", i, Byte2String(sc[:18]))
				var xor byte
				for _, v := range sc[:18] {
					xor ^= v
				}
				if xor == 0 {
					解密 = true
					if rt.日期KEY != di {
						rt.日期KEY = di
					}
					break
				}
				GetKey(KEY, di)
				Password(KEY, sc[:18], 0, 0) //还原前18个
			}
			if 解密 == false {
				panic(GetTime() + fmt.Sprintf("校验非法! 当前数据包:%s\r\n完整数据包:%s", Byte2String(sc), Byte2String(rx[:rxlen])))
			}
			maxlen := 0
			for i := 0; i < 7; i++ {
				var n int
				n = int(sc[2+i*2+1])
				n <<= 8
				n |= int(sc[2+i*2])
				maxlen += n
			}
			if (18 + maxlen) > len(sc) { //没接完呢,复制到缓冲区中
				break
			}
			编码 = Password(KEY, sc[:18+maxlen], 18, 编码) //整条数据解密
			sendbuff := CreateBuff(maxlen + 18)        //申请这一条的空间
			sendbuff.AddBytes(sc[:maxlen+18])          //复制这一条的内容
			if 是否调试 == true {
				fmt.Printf(GetTime()+"----[%04d]:%s\r\n", len(sendbuff.Buff), Byte2String(sendbuff.Buff))
			}
			sc = sc[len(sendbuff.Buff):] //必须这条在前,否则其它线程使用通讯很可能把sendbuff清空,造成这里出错
			rt.rxchan <- sendbuff
		}
		if len(sc) != 0 {
			for i, v := range sc {
				rx[i] = v
			}
			接收指针 = len(sc)
		}
	}
}

//将数据打包发送，自动添加标头和标尾,自动进行加密
func (rt *RunTime) AddHeadSend10(cmd byte, data [][]byte) {
	head := []byte{0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14}
	head[0] = cmd
	申请数组长度 := 0
	KEY := make([]byte, 256)
	for index, value := range data { //遍历数组
		if value == nil {
			continue
		}
		arrlen := len(value)
		申请数组长度 += arrlen
		head[(index+1)*2] = byte(arrlen)
		head[(index+1)*2+1] = byte(arrlen >> 8)
		if index == 0x01 {
			head[17] = head[5] ^ 0x14
		}
	}
	var xor byte
	if cmd == 0x04 { //登录时，发送角色信息时用这个指令
		head[17] = 0x00
		head[16] = head[4]
		for _, v := range head { //生成校验
			xor ^= v
		}
		head[17] = xor
	} else {
		for _, v := range head { //生成校验
			xor ^= v
		}
		head[16] = xor
	}
	arr := CreateBuff(申请数组长度)
	outs := ""
	是否调试 := false
	调试名称 := GetConfig("调试", "角色", "GM")
	if rt.V角色 != nil {
		if rt.V角色.V名字 == 调试名称 {
			是否调试 = true
		}
	}
	defer func() {
		if 是否调试 == true {
			fmt.Printf(GetTime()+"+%d+[%04d]:%s\r\n", rt.日期KEY, len(outs)/3, outs)
		}
	}()
	if 是否调试 == true {
		outs += Byte2String(head)
	}
	GetKey(KEY, rt.日期KEY)
	Password(KEY, head, 0, 0)
	arr.AddBytes(head)
	for _, value := range data { //遍历数组
		if value == nil {
			continue
		}
		if len(value) == 0 {
			continue
		}
		if 是否调试 == true {
			outs += Byte2String(value)
		}
		start := len(arr.Buff)
		arr.AddBytes(value) //先添加，后加密，这样不会变量冲突
		GetKey(KEY, rt.日期KEY)
		Password(KEY, arr.Buff[start:], 0, 0)
	}
	rt.txchan <- arr.Buff
}

//回应操作完成
func (rt *RunTime) Complete() {
	tx := CreateBuff(7)
	tx.AddInt16(0x00E2)
	tx.AddInt32(0)
	tx.AddByte(0)
	rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff})
}

//编号： 0E01  名称重复
func (rt *RunTime) 操作失败(编号 int16) {
	tx := CreateBuff(8)
	tx.AddInt16(0x00E2)
	tx.AddInt32(0x00)
	tx.AddInt16(编号)
	rt.AddHeadSend10(0x0A, [][]byte{{}, tx.Buff}) //发送错误消息
}

func UTF8ToGBK(s string) string {
	return mahonia.NewEncoder("gbk").ConvertString(s)
}
func GBKToUTF8(s string) string {
	return mahonia.NewDecoder("gbk").ConvertString(s)
}
